﻿using Kingdee.BOS;
using Kingdee.BOS.App.Core;
using Kingdee.BOS.Contracts;
using Kingdee.BOS.Core;
using Kingdee.BOS.Web.Core;
using Kingdee.BOS.Core.DynamicForm;
using Kingdee.BOS.Core.List;
using Kingdee.BOS.Core.Metadata;
using Kingdee.BOS.Log;
using Kingdee.BOS.ServiceFacade.KDServiceFx;
using Kingdee.BOS.Web.DynamicForm;
using Kingdee.BOS.Web.List;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Kingdee.BOS.Core.DynamicForm.PlugIn;
using Kingdee.BOS.Core.List.PlugIn;
using Kingdee.BOS.Core.ListFilter;
using Kingdee.BOS.Core.Const;
using Kingdee.BOS.Core.Metadata.FieldElement;
using Kingdee.BOS.Core.Permission;
using Kingdee.BOS.Core.Report;
using Kingdee.BOS.JSON;
using Kingdee.BOS.ServiceHelper.Excel;
using Kingdee.BOS.Util;
using Kingdee.BOS.Web.Printing;
using System.Data;
using System.IO;
using System.Text.RegularExpressions;
using Kingdee.BOS.FileServer.Core.Object;
using Kingdee.BOS.FileServer.ProxyService;

namespace RK.MySchedule.Local
{
    /// <summary>
    /// 【执行计划】引出列表数据并发送邮件
    /// https://vip.kingdee.com/article/345938598287195392
    /// </summary>
    public class ExportListDataAndSendEmailScheduleService : IScheduleService
    {
        public void Run(Context ctx, Schedule schedule)
        {
            try
            {
                // 设置组织(SELECT * FROM T_ORG_ORGANIZATIONS)
                ctx.CurrentOrganizationInfo = new OrganizationInfo
                {
                    ID = 1,
                    Name = "蓝海机械总公司"
                };
                // 设置用户(SELECT * FROM T_SEC_USER)
                ctx.UserId = 100008;
                ctx.UserName = "demo";
                // 设置单据
                var formId = "PUR_PurchaseOrder";
                // 设置过滤方案(SELECT * FROM T_BAS_FILTERSCHEME WHERE FFORMID='PUR_PurchaseOrder' AND FUSERID=100008)
                var schemeId = "62df6021e6f83e";
                // 创建列表视图
                var view = new ListViewBuilder().CreateListPrintView(ctx, formId, schemeId);
                // 生成引出数据
                var listExportService = new ListExportService(view);
                var filePath = listExportService.ExportData();
                // 发送邮件
                listExportService.SendMail(filePath);
            }
            catch (Exception ex)
            {
                Logger.Error("JAC", "引出列表数据时发生异常：" + ex.Message, ex);
                throw;
            }
        }
    }
    /// <summary>
    /// 列表视图构建器
    /// </summary>
    public class ListViewBuilder
    {
        /// <summary>
        /// 创建列表打印查询视图
        /// </summary>
        /// <param name="ctx"></param>
        /// <param name="formId"></param>
        /// <param name="schemeId"></param>
        /// <returns></returns>
        public IDynamicFormView CreateListPrintView(Context ctx, string formId, string schemeId)
        {
            // 构建报表窗体打开参数, 
            var formMetaData = (FormMetadata)new MetaDataService().Load(ctx, formId);
            // ShowParameter
            var showParam = new ListShowParameter();
            showParam.FormId = formId;
            showParam.PageId = Guid.NewGuid().ToString();
            var paraObj = showParam.CreateWebParams();
            // OpenParameter
            var dynamicFormMetaDataService = new DynamicFormMetaDataService();
            var sessionManager = new Kingdee.BOS.Web.Core.SessionManager();
            dynamicFormMetaDataService.SetContext(sessionManager, ctx);
            dynamicFormMetaDataService.FormMetaData = formMetaData;
            dynamicFormMetaDataService.GetDynamicFormConfig(paraObj);
            var openParam = sessionManager.Get<DynamicFormOpenParameter>(showParam.PageId, FormConst.OPEN_PARAM);
            openParam.SetCustomParameter("SessionManager", sessionManager);
            // 创建视图
            var rptView = new ListPrintWebService(schemeId, null, null);
            // 初始化视图
            var provider = GetListServiceProvider(openParam);
            rptView.Initialize(openParam, provider);
            rptView.LoadData();
            return rptView;
        }
        /// <summary>
        /// 获取报表服务提供者
        /// </summary>
        /// <returns></returns>
        private IResourceServiceProvider GetListServiceProvider(DynamicFormOpenParameter param)
        {
            var provider = new FormServiceProvider();
            provider.Add(typeof(IDynamicFormView), CreateListView(param));
            provider.Add(typeof(DynamicFormViewPlugInProxy), new ListViewPlugInProxy());
            provider.Add(typeof(DynamicFormModelPlugInProxy), new ListModelPlugInProxy());
            provider.Add(typeof(IDynamicFormModelService), GetListModel(param));
            provider.Add(typeof(IListFilterModelService), GetListFilterModel());
            var type = TypesContainer.GetOrRegister("Kingdee.BOS.Business.DynamicForm.DefaultValue.DefaultValueCalculator,Kingdee.BOS.Business.DynamicForm");
            provider.Add(typeof(IDefaultValueCalculator), Activator.CreateInstance(type));
            // 注册IDBModelService
            type = TypesContainer.GetOrRegister("Kingdee.BOS.Business.DynamicForm.DBModel.DBModelService,Kingdee.BOS.Business.DynamicForm");
            provider.Add(typeof(IDBModelService), Activator.CreateInstance(type));
            return provider;
        }
        /// <summary>
        /// 获取视图
        /// </summary>
        /// <returns></returns>
        private IDynamicFormView CreateListView(DynamicFormOpenParameter param)
        {
            var form = param.FormMetaData.BusinessInfo.GetForm();
            if (form.FormGroups != null && form.FormGroups.Count > 0)
            {
                return new TreeListView();
            }
            else
            {
                return new ListView();
            }
        }
        /// <summary>
        /// 获取视图模型
        /// </summary>
        /// <returns></returns>
        private IDynamicFormModelService GetListModel(DynamicFormOpenParameter param)
        {
            var form = param.FormMetaData.BusinessInfo.GetForm();
            if (form.FormGroups != null && form.FormGroups.Count > 0)
            {
                var type = TypesContainer.GetOrRegister("Kingdee.BOS.Model.List.TreeListModel,Kingdee.BOS.Model");
                return (IDynamicFormModelService)Activator.CreateInstance(type);
            }
            else
            {
                var type = TypesContainer.GetOrRegister("Kingdee.BOS.Model.List.ListModel,Kingdee.BOS.Model");
                return (IDynamicFormModelService)Activator.CreateInstance(type);
            }
        }
        /// <summary>
        /// 创建过滤条件模型
        /// </summary>
        /// <returns></returns>
        private IListFilterModelService GetListFilterModel()
        {
            var type = TypesContainer.GetOrRegister("Kingdee.BOS.Model.ListFilter.ListFilterModel,Kingdee.BOS.Model");
            return (IListFilterModelService)Activator.CreateInstance(type);
        }
    }

    /// <summary>
    /// 列表引出服务
    /// </summary>
    public class ListExportService
    {

        #region var

        #region const

        // 引出设置标识
        private const string STRSETUPINFO = "ExportSetting";

        #endregion

        // 引出文件类型
        private SaveFileType _fileType = SaveFileType.XLS;
        private string _outServicePath = "";
        private string _filePath = "";
        private string _directioy = "";

        /// <summary>
        /// 待执行引出取数操作的视图
        /// </summary>
        private IDynamicFormView view;

        #endregion

        public ListExportService(IDynamicFormView listView)
        {
            this.view = listView;
        }

        /// <summary>
        /// 创建列表引出文件
        /// </summary>
        /// <returns></returns>
        public string ExportData()
        {
            Logger.Info("JAC", view.BillBusinessInfo.GetForm().Name + "列表引出开始");
            InitVariable();
            using (ExcelOperation helper = new ExcelOperation(view))
            {
                var count = BOSConst.DefaultAllRowCount;
                var listJson = ((IListViewService)view).GetExportData(0, count, PermissionConst.Export, false);
                if (!listJson.ContainsKey("rows"))
                {
                    throw new KDException("###", string.Format("您没有“{0}”的“引出”权限！", view.BillBusinessInfo.GetForm().Name));
                }

                var rows = (JSONArray)listJson["rows"];
                if (rows.Count == 0)
                {
                    //throw new KDException("###", "没有可以引出的数据，请确认在查询的组织范围内有引出当前单据的权限。");
                    return string.Empty;
                }

                var ListField = new List<ExcelField>();
                var dt = new DataTable();
                var columnIndexs = new List<int>();
                var exportTypeList = new List<ExportDataType>();
                GetListExportConfigInfo(ListField, dt, columnIndexs, exportTypeList);
                GetTable(ref dt, columnIndexs, rows, exportTypeList);
                int maxrowcount = GetBillCountPerExportFile();
                List<string> columnsNames = ListField.Select(p => p.Caption).ToList();
                if (dt.Rows.Count > maxrowcount)
                {
                    using (ExcelOperation helper2 = new ExcelOperation(view))
                    {
                        helper2.BeginExport();
                        //此处构建dataset,使用通用接口来做拆分大量数据
                        using (DataSet ds = ReBuildExportListData(dt, columnsNames, maxrowcount, null))
                        {
                            dt.Dispose();
                            helper2.DateSetToExcel(ds, false);
                            //按用户配置的引出文件类型引出文件
                            helper2.EndExport(_filePath, _fileType);
                        }

                        //helper2.DownLoadFile(OutServicePath);
                    }
                }
                else
                {
                    helper.BeginExport();
                    helper.FillColumnName(columnsNames);
                    helper.ExportToFile(dt);
                    //按用户配置的引出文件类型引出文件
                    helper.EndExport(_filePath, _fileType);
                    // helper.DownLoadFile(OutServicePath);
                }
            }

            Logger.Info("JAC", view.BillBusinessInfo.GetForm().Name + "列表引出成功：" + _filePath);
            return _filePath;
        }

        /// <summary>
        /// 发送邮件
        /// 参考：https://vip.kingdee.com/article/131834587734451200
        /// </summary>
        public void SendMail(string filePath)
        {
            var sendMailService = new SendMailService();
            // 获取邮件服务器信息，发件人信息
            var emailInfo = sendMailService.GetEmailMessageInfoByUserId(view.Context, view.Context.UserId);
            // 设置邮件标题
            emailInfo.Subject = "采购订单列表引出数据";
            // 设置邮件内容
            emailInfo.Body = string.Format("单据名称：采购订单\r\n导出人：{0}\r\n导出时间：{1}", view.Context.UserName, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            // 设置邮件接收人
            emailInfo.To = new List<string>();
            emailInfo.To.Add("888888@qq.com");
            // 设置邮件抄送人
            //emailInfo.Cc = new List<string>();
            //emailInfo.Cc.Add("999999@qq.com");
            // 设置邮件附件信息
            if (!string.IsNullOrWhiteSpace(filePath) && File.Exists(filePath))
            {
                emailInfo.Attachments = new List<string>();
                emailInfo.Attachments.Add(_filePath);
            }
            else
            {
                emailInfo.Body += "\r\n本次操作未查询到满足条件的数据，无引出文件。";
            }

            MailUtils.Sendmail(emailInfo);
            Logger.Info("JAC", view.BillBusinessInfo.GetForm().Name + "邮件发送成功：" + _filePath);
        }

        private void InitVariable()
        {
            _fileType = GetSaveType(view.BillBusinessInfo.GetForm().Id);
            _directioy = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, KeyConst.TEMPFILEPATH);
            string fileName = string.Format("{0}_{1}", view.BillBusinessInfo.GetForm().Name, DateTime.Now.ToString("yyyyMMddHHmmssff"));
            fileName = PathUtils.GetValidFileName(fileName);
            //按用户设置的引出文件类型引出对应的文件,默认是Excel2003（.xls）
            if (this._fileType == SaveFileType.XLSX)
            {
                fileName += ".xlsx";
            }
            else
            {
                fileName += ".xls";
            }

            _outServicePath = PathUtils.GetServerPath(KeyConst.TEMPFILEPATH, PathUtils.UrlEncode(fileName));
            _filePath = PathUtils.GetPhysicalPath(KeyConst.TEMPFILEPATH, fileName);
            InitDirectioy();
        }

        /// <summary>
        /// 生成列表引出配置信息
        /// </summary>
        /// <param name="ListField"></param>
        /// <param name="dt"></param>
        /// <param name="columnIndexs"></param>
        /// <param name="exportTypeList"></param>
        private void GetListExportConfigInfo(List<ExcelField> ListField, DataTable dt, List<int> columnIndexs, List<ExportDataType> exportTypeList)
        {
            ListHeader header = ((IListModel)view.Model).Header;
            if (header != null && header.GetChildCount() > 0)
            {
                for (int i = 0; i < header.GetChilds().Count; i++)
                {
                    ListHeader h = header.GetChilds()[i];
                    if (h.Visible)
                    {
                        ListField.Add(
                            new ExcelField()
                            {
                                FieldName = h.FieldName,
                                Caption = h.Caption
                            });
                        if (h.FieldAppearance is ImageFieldAppearance)
                        {
                            dt.Columns.Add(h.FieldName, typeof(Byte[]));
                            exportTypeList.Add(ExportDataType.DatabaseImage);
                        }
                        else if (h.FieldAppearance is ImageFileServerFieldAppearance
                                 || h.FieldAppearance is PictureFieldAppearance)
                        {
                            dt.Columns.Add(h.FieldName, typeof(Byte[]));
                            exportTypeList.Add(ExportDataType.FileServerImage);
                        }
                        else
                        {
                            dt.Columns.Add(h.FieldName);
                            exportTypeList.Add(ExportDataType.CommonData);
                        }

                        columnIndexs.Add(i);
                    }
                }
            }
        }

        private void GetTable(ref System.Data.DataTable dt, List<int> columnIndexs, JSONArray rows, List<ExportDataType> exportTypeList)
        {
            bool allowdSOSeq = false;
            if (view.Model.ParameterData != null && view.Model.ParameterData.DynamicObjectType.Properties.ContainsKey(KeyConst.FALLOWDSPSEQ_KEY))
            {
                Boolean.TryParse(view.Model.ParameterData[KeyConst.FALLOWDSPSEQ_KEY].ToString(), out allowdSOSeq);
            }

            for (int i = 0; i < rows.Count; i++)
            {
                DataRow newRow = dt.NewRow();
                for (int j = 0; j < columnIndexs.Count; j++)
                {
                    int colIndex = columnIndexs[j];
                    if (allowdSOSeq)
                    {
                        //显示序号，列索引需要增加1
                        colIndex = columnIndexs[j] + 1;
                    }

                    if (exportTypeList[j] == ExportDataType.CommonData)
                    {
                        newRow[j] = ((JSONArray)rows[i])[colIndex];
                    }
                    else if (exportTypeList[j] == ExportDataType.DatabaseImage)
                    {
                        newRow[j] = Convert.FromBase64String(((JSONArray)rows[i])[colIndex].ToString());
                    }
                    else if (exportTypeList[j] == ExportDataType.FileServerImage)
                    {
                        string downloadUrl = ((JSONArray)rows[i])[colIndex].ToString();
                        Regex regex = new Regex(@"(?<=fileId=)[\w]+", RegexOptions.IgnoreCase);
                        string fileId = regex.Match(downloadUrl).GetString();

                        byte[] byteData = GetImageByte(view.Context, fileId);
                        newRow[j] = byteData;
                    }
                }

                dt.Rows.Add(newRow);
            }
        }

        /// <summary>
        /// 获取图片字节流数据
        /// </summary>
        private byte[] GetImageByte(Context ctx, string fileId)
        {
            if (!string.IsNullOrWhiteSpace(fileId))
            {
                try
                {
                    TFileInfo tFile = new TFileInfo { FileId = fileId, CTX = ctx };
                    return new UpDownloadService().GetFileData(tFile);
                }
                catch
                {
                    return null;
                }
            }

            return null;
        }

        /// <summary>
        /// 获取配置文件中每个引出文件容纳的最大单据数
        /// </summary>
        /// <returns></returns>
        private int GetBillCountPerExportFile()
        {
            int iBillCountPerExportFile = KDConfiguration.Current.BillCountPerExportFile;
            if (iBillCountPerExportFile > 100000)
            {
                return 100000;
            }

            return iBillCountPerExportFile;
        }

        /// <summary>
        /// 初始化引出文件存放的文件夹，没有则创建
        /// </summary>
        private void InitDirectioy()
        {
            string directioy = _directioy;
            if (Directory.Exists(directioy) == false)
            {
                Directory.CreateDirectory(directioy);
            }
        }

        /// <summary>
        /// 重新构建列表引出的数据，取消掉所有的格式
        /// </summary>
        /// <returns></returns>
        private DataSet ReBuildExportListData(DataTable dt, List<string> columnnames, int maxrowcount, List<ListHeader> listHeaders)
        {
            DataSet ds = new DataSet();
            DataTable subdt;
            if (listHeaders != null)
            {
                subdt = new System.Data.DataTable();
                for (int i = 0; i < listHeaders.Count; i++)
                {
                    string fieldName = listHeaders[i].FieldName;
                    if (dt.Columns.Contains(fieldName))
                    {
                        DataColumn column = new DataColumn(fieldName, dt.Columns[fieldName].DataType);
                        subdt.Columns.Add(column);
                    }
                }
            }
            else
            {
                subdt = dt.Clone();
            }

            int count = 1;
            string tablename = view.BillBusinessInfo.GetForm().Name;
            subdt.TableName = string.Format("{0}_Part{1}", tablename, count);
            int idx = 0;
            foreach (DataRow dr in dt.Rows)
            {
                if (idx == 0)
                {
                    DataRow rowname = subdt.NewRow();
                    for (int i = 0; i < columnnames.Count(); i++)
                    {
                        rowname[i] = columnnames[i];
                    }

                    subdt.Rows.Add(rowname);
                }

                DataRow row = subdt.NewRow();
                foreach (DataColumn col in subdt.Columns)
                {
                    row[col] = dr[col.ColumnName];
                }

                subdt.Rows.Add(row);
                idx++;
                if (idx == maxrowcount)
                {
                    idx = 0;
                    ds.Tables.Add(subdt);

                    subdt = subdt.Clone();
                    count++;
                    subdt.TableName = string.Format("{0}_Part{1}", tablename, count);
                }
            }

            if (subdt.Rows.Count > 0)
            {
                ds.Tables.Add(subdt);
            }

            return ds;
        }

        /// <summary>
        /// 获取用户配置的引出文件格式
        /// </summary>
        /// <param name="formId"></param>
        /// <returns></returns>
        protected SaveFileType GetSaveType(string formId)
        {
            var info = Kingdee.BOS.ServiceHelper.UserParamterServiceHelper.Load(this.view.Context, STRSETUPINFO + formId.ToUpperInvariant().GetHashCode().ToString(), this.view.Context.UserId);
            if (!string.IsNullOrWhiteSpace(info) && info != "<Root />")
            {
                JSONArray jsonArray = new JSONArray(info);
                string fileTypeValue = GetValuebyKey(jsonArray, "filetype");
                if (!fileTypeValue.IsNullOrEmpty())
                {
                    SaveFileType type;
                    if (Enum.TryParse(fileTypeValue, out type))
                    {
                        return type;
                    }
                }
            }

            return SaveFileType.XLSX;
        }

        /// <summary>
        /// JSON数组中按键值取数
        /// </summary>
        /// <param name="jsonArray"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        private string GetValuebyKey(JSONArray jsonArray, string key)
        {
            string result = string.Empty;
            if (jsonArray == null)
            {
                return result;
            }

            for (int i = 0; i < jsonArray.Count; i++)
            {
                Dictionary<string, object> obj = jsonArray[i] as Dictionary<string, object>;
                if (obj != null && obj["key"] != null && obj["key"].ToString() == key)
                {
                    result = ObjectUtils.Object2String(obj["value"]);
                    break;
                }
            }

            return result;
        }
    }
}
